/*
 * Cerdito.cpp
 *
 *  Created on: 16/10/2012
 *      Author: Ignacio Galvez
 */

#include "Cerdito.h"
#include "HuevoBlanco.h"
#include "HuevoCodorniz.h"
#include "HuevoPoche.h"
#include "HuevoReloj.h"
#include <cmath>
#include <cstdio>
#include <iostream>
#define  ALFA_LIMITE_1_CUADRANTE 1.40
#define  ALFA_LIMITE_2_CUADRANTE 1.75
#define G 10.0


Cerdito::Cerdito( int id, double x, double y)
:Daniable(VIDA_CERDITO,x, y), id(id),posicionXfinal(-1),
posicionYfinal(-1) {}

double Cerdito::DANIO_HUEVO_RELOJ = 2;
double Cerdito::EXPLOSION_HUEVO_BLANCO = 0.5;
double Cerdito::DANIO_PAJARO_ROJO = 1;
double Cerdito::DANIO_PAJARO_VERDE = 2;
double Cerdito::DANIO_PAJARO_AZUL = 1;
double Cerdito::VIDA_CERDITO = 5;
void Cerdito::serDaniadoPorPajaroRojo() {}
void Cerdito::serDaniadoPorPajaroVerde() {}
void Cerdito::serDaniadoPorPajaroAzul() {}
void Cerdito::serDaniadoPorHuevoBlanco() {}
void Cerdito::serDaniadoPorHuevoCodorniz() {}
void Cerdito::serDaniadoPorHuevoPoche() {}
void Cerdito::serDaniadoPorHuevoReloj() {}
void Cerdito::recibirExplosionHuevoBlanco() {
	disminuirPuntosDeVida(EXPLOSION_HUEVO_BLANCO);
}

/*Si el disparo es vertical u horizontal este no se realiza */
bool Cerdito::puedeDisparar(double x, double y) {
	return ((getPosicionX() - x) != 0) || ((getPosicionY() - y) != 0);
}

void  Cerdito::generarHuevoBlanco() {
Huevo* huevo;
double anguloDeTiro;
double normaVelocidadInicial;
anguloDeTiro = calcularAnguloDeTiro(posicionXfinal, posicionYfinal);
normaVelocidadInicial = calcularVelocidadInicial(anguloDeTiro, 
	posicionXfinal, posicionYfinal);
huevo = new HuevoBlanco(anguloDeTiro, normaVelocidadInicial,
		getPosicionX(), getPosicionY(), tiempoActual);
huevos.push_back(huevo);
}

void  Cerdito::generarHuevoPoche() {
Huevo* huevo;
double anguloDeTiro;
double normaVelocidadInicial;
anguloDeTiro = calcularAnguloDeTiro(posicionXfinal, posicionYfinal);
normaVelocidadInicial = calcularVelocidadInicial(anguloDeTiro, 
	posicionXfinal, posicionYfinal);
huevo = new HuevoPoche(anguloDeTiro, normaVelocidadInicial,
		getPosicionX(), getPosicionY(), tiempoActual);
huevos.push_back(huevo);
}
void  Cerdito::generarHuevoReloj() {
Huevo* huevo;
double anguloDeTiro;
double normaVelocidadInicial;
anguloDeTiro = calcularAnguloDeTiro(posicionXfinal, posicionYfinal);
normaVelocidadInicial = calcularVelocidadInicial(anguloDeTiro, 
	posicionXfinal, posicionYfinal);
huevo = new HuevoReloj(anguloDeTiro, normaVelocidadInicial,
		getPosicionX(), getPosicionY(), tiempoActual);
huevos.push_back(huevo);
}
void  Cerdito::generarHuevosCodorniz() {
Huevo* huevo;
const double factor1 = 3;
const double factor2 = 4;
const double factor3 = 5;
double anguloDeTiro0 = calcularAnguloDeTiro(posicionXfinal, posicionYfinal);
double anguloDeTiro1 = calcularAnguloDeTiro(posicionXfinal, posicionYfinal, factor1);
double anguloDeTiro2 = calcularAnguloDeTiro(posicionXfinal, posicionYfinal, factor2);
double anguloDeTiro3 = calcularAnguloDeTiro(posicionXfinal, posicionYfinal, factor3);
double normaVelocidadInicial0 = calcularVelocidadInicial(anguloDeTiro0, posicionXfinal, 
	posicionYfinal);
double normaVelocidadInicial1 = calcularVelocidadInicial(anguloDeTiro1, posicionXfinal, 
	posicionYfinal);
double normaVelocidadInicial2 = calcularVelocidadInicial(anguloDeTiro2, posicionXfinal, 
	posicionYfinal);
double normaVelocidadInicial3 = calcularVelocidadInicial(anguloDeTiro3, posicionXfinal, 
	posicionYfinal);
huevo = new HuevoCodorniz(anguloDeTiro0, normaVelocidadInicial0, getPosicionX(), 
	getPosicionY(), tiempoActual);
	huevos.push_back(huevo);
huevo = new HuevoCodorniz(anguloDeTiro1, normaVelocidadInicial1, getPosicionX(), 
	getPosicionY(), tiempoActual);
	huevos.push_back(huevo);
huevo = new HuevoCodorniz(anguloDeTiro2, normaVelocidadInicial2, getPosicionX(), 
	getPosicionY(), tiempoActual);
	huevos.push_back(huevo);
huevo = new HuevoCodorniz(anguloDeTiro3, normaVelocidadInicial3, getPosicionX(), 
	getPosicionY(), tiempoActual);
	huevos.push_back(huevo);

}
double Cerdito::tiempoActual = 0;
void Cerdito::incrementarTiempoActual() {
	const double deltaT = 0.1;
	tiempoActual += deltaT;
}

void Cerdito::show() {}

double Cerdito::calcularAnguloDeTiro(double x, double y) {
	double diferenciax;
	double diferenciay;
	double tangenteangulocritico;
	double alfacradianes;
	double alfaradianes;
	double beta;
	double gammacritica;
	const double anguloIncorrecto = -1;
	diferenciax = (x - getPosicionX());
	diferenciay = (y - getPosicionY());
	if ((diferenciax > 0)&&(diferenciay > 0)){
		// caso de angulo en primer cuadrante
		tangenteangulocritico = diferenciay / diferenciax;
		std::cout <<" tangenteangulocritico "<< tangenteangulocritico <<std::endl;
		alfacradianes = atan(tangenteangulocritico);
		std::cout <<" alfacradianes "<< alfacradianes <<std::endl;
		beta = M_PI_2 - alfacradianes;
		std::cout <<" beta "<< beta <<std::endl;
		alfaradianes = alfacradianes + beta / 2;
		std::cout <<" alfaradianes "<< alfaradianes <<std::endl;
		if (alfaradianes > ALFA_LIMITE_1_CUADRANTE)
			alfaradianes = ALFA_LIMITE_1_CUADRANTE;
		return alfaradianes;
	}
	if ((diferenciax < 0)&&(diferenciay > 0)){
		// caso del segundo cuadrante
		std::cout << "segundo cuadrante" << std::endl;
		tangenteangulocritico = diferenciay/diferenciax;
		std::cout <<" tangenteangulocritico "<< tangenteangulocritico <<std::endl;
		alfacradianes = atan(tangenteangulocritico);
		std::cout <<" alfacradianes "<< alfacradianes <<std::endl;
		gammacritica = M_PI + alfacradianes;
		std::cout <<" gammacritica "<< gammacritica <<std::endl;
		beta = M_PI_2 + alfacradianes;
		std::cout <<" beta "<< beta <<std::endl;
		alfaradianes = gammacritica - fabs(beta / 2);
		if (alfaradianes < ALFA_LIMITE_2_CUADRANTE)
			alfaradianes = ALFA_LIMITE_2_CUADRANTE;
		std::cout <<" alfaradianes "<< alfaradianes <<std::endl;
		return alfaradianes;
	}
	if ((diferenciax < 0)&&(diferenciay < 0)){
		// caso angulo tercer cuadrante
		tangenteangulocritico = diferenciay / diferenciax;
		std::cout <<" tangenteangulocritico "<< tangenteangulocritico <<std::endl;
		alfacradianes = atan(tangenteangulocritico);
		std::cout <<" alfacradianes "<< alfacradianes <<std::endl;
		gammacritica = M_PI + alfacradianes;
		std::cout <<" gammacritica "<< gammacritica <<std::endl;
		beta = fabs(alfacradianes) / 2;
		std::cout <<" beta "<< beta <<std::endl;
		alfaradianes = gammacritica - beta;
		std::cout <<" alfaradianes "<< alfaradianes <<std::endl;
		return alfaradianes;
	}

	if ((diferenciax>0)&&(diferenciay<0)){
		// caso angulo cuarto cuadrante
		tangenteangulocritico=diferenciay/diferenciax;
		std::cout <<" tangenteangulocritico "<< tangenteangulocritico <<std::endl;
		alfacradianes = atan(tangenteangulocritico);
		std::cout <<" alfacradianes "<< alfacradianes <<std::endl;
		gammacritica = 2 * M_PI + alfacradianes;
		std::cout <<" gammacritica "<< gammacritica <<std::endl;
		beta = fabs(alfacradianes) / 2;
		std::cout <<" beta "<< beta <<std::endl;
		alfaradianes = gammacritica + beta;
		std::cout <<" alfaradianes "<< alfaradianes <<std::endl;
		return alfaradianes;
	}
return anguloIncorrecto;
}

double Cerdito::calcularAnguloDeTiro(double x, double y, double factor) {
	double diferenciax;
	double diferenciay;
	double tangenteangulocritico;
	double alfacradianes;
	double alfaradianes;
	double beta;
	double gammacritica;
	const double anguloIncorrecto = -1;
	diferenciax = (x - getPosicionX());
	diferenciay = (y - getPosicionY());
	if ((diferenciax > 0)&&(diferenciay > 0)){
		// caso de angulo en primer cuadrante
		tangenteangulocritico = diferenciay / diferenciax;
		std::cout <<" tangenteangulocritico "<< tangenteangulocritico <<std::endl;
		alfacradianes = atan(tangenteangulocritico);
		std::cout <<" alfacradianes "<< alfacradianes <<std::endl;
		beta = M_PI_2 - alfacradianes;
		std::cout <<" beta "<< beta <<std::endl;
		alfaradianes = alfacradianes + beta / factor;
		std::cout <<" alfaradianes "<< alfaradianes <<std::endl;
		if (alfaradianes > ALFA_LIMITE_1_CUADRANTE)
			alfaradianes = ALFA_LIMITE_1_CUADRANTE;
		return alfaradianes;
	}
	if ((diferenciax < 0)&&(diferenciay > 0)){
		// caso del segundo cuadrante
		std::cout << "segundo cuadrante" << std::endl;
		tangenteangulocritico = diferenciay/diferenciax;
		std::cout <<" tangenteangulocritico "<< tangenteangulocritico <<std::endl;
		alfacradianes = atan(tangenteangulocritico);
		std::cout <<" alfacradianes "<< alfacradianes <<std::endl;
		gammacritica = M_PI + alfacradianes;
		std::cout <<" gammacritica "<< gammacritica <<std::endl;
		beta = M_PI_2 + alfacradianes;
		std::cout <<" beta "<< beta <<std::endl;
		alfaradianes = gammacritica - fabs(beta / factor);
		if (alfaradianes < ALFA_LIMITE_2_CUADRANTE)
			alfaradianes = ALFA_LIMITE_2_CUADRANTE;
		std::cout <<" alfaradianes "<< alfaradianes <<std::endl;
		return alfaradianes;
	}
	if ((diferenciax < 0)&&(diferenciay < 0)){
		// caso angulo tercer cuadrante
		tangenteangulocritico = diferenciay / diferenciax;
		std::cout <<" tangenteangulocritico "<< tangenteangulocritico <<std::endl;
		alfacradianes = atan(tangenteangulocritico);
		std::cout <<" alfacradianes "<< alfacradianes <<std::endl;
		gammacritica = M_PI + alfacradianes;
		std::cout <<" gammacritica "<< gammacritica <<std::endl;
		beta = fabs(alfacradianes) / factor;
		std::cout <<" beta "<< beta <<std::endl;
		alfaradianes = gammacritica - beta;
		std::cout <<" alfaradianes "<< alfaradianes <<std::endl;
		return alfaradianes;
	}

	if ((diferenciax>0)&&(diferenciay<0)){
		// caso angulo cuarto cuadrante
		tangenteangulocritico=diferenciay/diferenciax;
		std::cout <<" tangenteangulocritico "<< tangenteangulocritico <<std::endl;
		alfacradianes = atan(tangenteangulocritico);
		std::cout <<" alfacradianes "<< alfacradianes <<std::endl;
		gammacritica = 2 * M_PI + alfacradianes;
		std::cout <<" gammacritica "<< gammacritica <<std::endl;
		beta = fabs(alfacradianes) / factor;
		std::cout <<" beta "<< beta <<std::endl;
		alfaradianes = gammacritica + beta;
		std::cout <<" alfaradianes "<< alfaradianes <<std::endl;
		return alfaradianes;
	}
return anguloIncorrecto;
}

//std::string & Cerdito::getImagePath() {}
void  Cerdito::setImagePath(std::string &path) {}

void Cerdito::disparar(double posicionXfinal, double posicionYfinal) {
	if (puedeDisparar(posicionXfinal,posicionYfinal)) {
		disparo = true;
		this->posicionXfinal = posicionXfinal;
		this->posicionYfinal = posicionYfinal;
	}
}

double Cerdito::calcularVelocidadInicial(double anguloDeTiro, double x,
		double y) {
	double datosx1;
	double datosx2;
	double datosy1;
	double tangente;
	double cosenocuadrado;
	double tangenteLimite;
	double constante;
	double denominador;
	double numerador;
	double V0cuadrado;
	double V0;
	const double V0Minimo = 10;
	const double V0Maximo = 300;
	const double anguloIncorrecto =  -1;
	datosx2 = pow(fabs(x - getPosicionX()), 2);
	datosx1 = (x - getPosicionX());
	datosy1 = (y - getPosicionY());
	tangente = tan(anguloDeTiro);
	std::cout << "tangente "<<tangente<< std::endl;
// Analisis si el alcance es posible
// calculo tangente limite
	tangenteLimite = datosy1 / datosx1;
	std::cout<<"tangenteLimite"<<tangenteLimite<<std::endl;
	if (((datosx1 > 0) && (tangenteLimite < tangente))||((datosx1 < 0) && 
		(tangenteLimite > tangente))) {
		cosenocuadrado = pow(cos(anguloDeTiro), 2);
		std::cout<< "cosenocuadrado "<< cosenocuadrado << std::endl;
		constante = G / 2.0;
		numerador = constante * datosx2;
		std::cout << "numerador " << numerador <<std::endl;
		denominador = (tangente * datosx1 - datosy1) * cosenocuadrado;
		std::cout << "denominador "<< denominador <<std::endl;
		V0cuadrado = numerador / denominador;
		if (V0cuadrado >= 0) {
			//std::cout<<"V0cuadrado es menor que cero"<<std::endl;
			//return -1;
			V0 = pow(V0cuadrado, 0.5);
			std::cout << " V0 "<< V0 << std::endl;
			if (V0 < V0Minimo) V0 = V0Minimo;
			if (V0 > V0Maximo) V0 = V0Maximo;
			return V0;
		}
		else return anguloIncorrecto;
	}
	else return anguloIncorrecto;
}
bool Cerdito::dispara() {
	return disparo;
}

std::list<Huevo*> Cerdito::disparar(){
	return huevos;
}


Cerdito::~Cerdito() {}


